import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:dio/dio.dart';
import 'package:erp/DataInterface/Events/NetworkCommunicationEvents.dart';
import 'package:erp/DataInterface/Interfaces.dart';
import 'package:erp/Entity/Customer.dart';
import 'package:erp/Entity/CustomerType.dart';
import 'package:erp/Entity/Product.dart';
import 'package:erp/Entity/CountResult.dart';
import 'package:erp/Entity/ProductDetailAtPurchaseOrSell.dart';
import 'package:erp/Entity/ProductInWareHouse.dart';
import 'package:erp/Entity/ProductType.dart';
import 'package:erp/Entity/PurchaseOrder.dart';
import 'package:erp/Entity/SalesDetailsProductGroup.dart';
import 'package:erp/Entity/SalesOrder.dart';
import 'package:erp/Entity/ServerResponse.dart';
import 'package:erp/Entity/ServerTime.dart';
import 'package:erp/Entity/SignInResult.dart';
import 'package:erp/Entity/Supplier.dart';
import 'package:erp/Entity/SupplierType.dart';
import 'package:erp/Entity/WareHouse.dart';
import 'package:erp/Extensions/DateTime.dart';
import 'package:erp/Store/AccountStore.dart';
import 'package:erp/UI/Pages/SettingsPages/ServerSettingsPage.dart';
import 'package:erp/global.dart';
import 'package:intl/intl.dart';


//region For Security, also it`s not am writed

String ENCODE_TOKEN = "OMTAeJjuTkFnmFujYCDGwg==";

String _getToken(String phoneNumber, String password, String time){

  String encode(String str)
  {

    Uint8List bufferKey = utf8.encode(ENCODE_TOKEN);
    Uint8List bufferStr = utf8.encode(str);

    for (int i = 0, size = bufferStr.length; i < size; i++)
    {
      bufferKey.forEach((buffer){
        bufferStr[i] = (bufferStr[i] ^ buffer);
      });
    }

    String result = "";
    bufferStr.forEach((buff){
      result += String.fromCharCode(buff);
    });
    return result;
  }

  String format(String str, String time)
  {
    String result = ""; //返回数据
    String last = ""; //超载部分
    int lenTime = time.length;
    int lenStr = str.length;
    int minLen;
    int maxLen;

    if (lenStr < lenTime)
    {
      minLen = lenStr;
      maxLen = lenTime;
      last = time;
    }
    else
    {
      maxLen = lenStr;
      minLen = lenTime;
      last = str;
    }
    for (int i = 0; i < minLen; i++)
    {
      result += (time.substring(i, i + 1) + str.substring(i, i + 1));
    }
    var firstIndex = last.length - (maxLen - minLen);
    result = last.substring(firstIndex, firstIndex + (maxLen - minLen)) + ENCODE_TOKEN + result + ENCODE_TOKEN + (lenTime > lenStr ? "1" : "0");
    return encode(result);
  }

  String result = json.encode({
    "phone": format(phoneNumber, time),"password": format(password, time)
  });

  return encode(result);
}
//endregion



class HttpInterfaces implements Interfaces {

  var dio0 = Dio(Options(
    baseUrl: "${globalPreferences.get(SERVER_IP_KEY)}/api",
    connectTimeout: globalPreferences.get(SERVER_TIMEOUT_KEY),
  ));

  Map<String, dynamic> resolveToJson(Object value){
    var result = {};
    if (value is String){
      result = json.decode(value);
    }
    else
      result = value;
    return result;
  }

  void resolveImageUrl<T>(T object, String propertySelector(T object), void resolvedUrl(T object, String url)){
    var oldUrl = propertySelector(object);
    var newUrl = "${globalPreferences.get(SERVER_IP_KEY)}/$oldUrl";
    resolvedUrl(object, oldUrl == null ? null : newUrl);
  }

  HttpInterfaces(){
    registerNetworkCommunicationEvents(); //Register network connection
  }

  @override
  Future<void> getTime(void callback(ServerTime time)) async {
    var response = await dio0.post<String>("/common/datetime", data: {
      "token": ENCODE_TOKEN
    });
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    callback(ServerResponse.fromJson(json.decode(response.data), (jsonProperty) => ServerTime.fromJson(jsonProperty)).msg);
  }

  @override
  Future<void> signIn(String userName, String password, void Function(ServerResponse<SignInResult> signInResult) callback) async {
    await getTime((time) async {
      var token = _getToken(userName, password, time.time ?? "");

      var response = await dio0.post("/employee/login", data: FormData.from({
        "flag": "mobile",
        "token": token,
        "mobilenumber": "123456"
      }));
      globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
      callback(ServerResponse.fromJson(resolveToJson(response.data), (jsonProperty) => SignInResult.fromJson(jsonProperty)));
    });
  }

  @override
  Future<CountResult> getAllProductCount(String token) async {
    var response = await (dio0.post("/product/pager?token=$token"));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    return ServerResponse<CountResult>.fromJson(resolveToJson(response.data), (json) => CountResult.fromJson(json)).msg;
  }

  @override
  Future<List<Product>> getProducts(String token, [int pageIndex = 0]) async {
    var response = await dio0.post("/product/select?token=$token", data: FormData.from({
      "page": pageIndex
    }));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse<List<Product>>.fromJson(resolveToJson(response.data), (json) => List.from((json as List<dynamic>).map((item) => Product.fromJson(item)).toList()));
    data.msg.forEach((product) => resolveImageUrl<Product>(product, (obj) => obj.imgurl, (obj, resolvedUrl) => obj.imgurl = resolvedUrl));
    return data.msg;
  }

  @override
  Future<List<ProductType>> getProductTypes(String token) async {
    var response = await dio0.post("/protype/select?token=$token");
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse<List<ProductType>>.fromJson(resolveToJson(response.data), (json) => List.from((json as List<dynamic>).map((item) => ProductType.fromJson(item)).toList())).msg;
    data.forEach((type) => resolveImageUrl<ProductType>(type, (obj) => obj.imgurl, (obj, resolvedUrl) => obj.imgurl = resolvedUrl));
    return data;
  }

  @override
  Future<ProductType> addProductType(String token, ProductType type) async {

    var response = await dio0.post("/protype/add?token=$token", data: FormData.from({
      "name": type.name,
      "imgurl": type.imgurl
    }));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse<ProductType>.fromJson(resolveToJson(response.data), (json) => ProductType.fromJson(json));
    resolveImageUrl<ProductType>(data.msg, (obj) => obj.imgurl, (obj, resolvedUrl) => obj.imgurl = resolvedUrl);
    return data.msg;
  }

  @override
  Future<ProductType> updateProductType(String token, ProductType type) async {
    var formData = {
      "id": type.id,
      "name": type.name,
    };
    if (type.imgurl.length > 100) formData["imgurl"] = type.imgurl;

    var response = await dio0.post("/protype/edit?token=$token", data: FormData.from(formData));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse<ProductType>.fromJson(resolveToJson(response.data), (json) => ProductType.fromJson(json));
    if (!data.type) throw data.msgText;
    resolveImageUrl<ProductType>(data.msg, (obj) => obj.imgurl, (obj, resolvedUrl) => obj.imgurl = resolvedUrl);
    return data.msg;
  }

  @override
  Future<ProductType> deleteProductType(String token, ProductType type) async {
    var response = await dio0.post("/protype/delete?token=$token", data: FormData.from({
      "id": type.id
    }));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse<int>.fromJson(resolveToJson(response.data), (json) => json as int);
    if (!data.type) throw data.msgText;
    return type;
  }

  @override
  Future<Product> addProduct(String token, Product product) async {
     var response = await dio0.post("/product/add?token=$token", data: FormData.from(product.toJson()));
     response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
     var data = ServerResponse<Product>.fromJson(resolveToJson(response.data), (json) => Product.fromJson(json));
     if (!data.type) throw data.msgText;
     resolveImageUrl<Product>(data.msg, (obj) => obj.imgurl, (obj, resolvedUrl) => obj.imgurl = resolvedUrl);
     return data.msg;
  }

  @override
  Future<String> generateNewProductCode(String token) async {
    var response = await dio0.post("/product/getnewprocode?token=$token");
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var productCode = ServerResponse.fromJson(resolveToJson(response.data), (json) => (json as Map<String, dynamic>)["procode"] as String);
    return productCode.msg;
  }

  @override
  Future<void> deleteProduct(String token, Product product) async {
    var response = await dio0.post("/product/delete?token=$token", data: FormData.from({
      "id": product.id
    }));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => true);
    if (!data.type) throw Exception(data.msgText);
    return;
  }

  @override
  Future<Product> updateProduct(String token, Product product) async {
    var formData = product.toJson();
    if (product.imgurl.length < 101){
      formData.remove("imgurl");
    }
    var response = await dio0.post("/product/edit?token=$token", data: FormData.from(formData));
    globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);

    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => Product.fromJson(json));

    if (!data.type) throw data.msgText;
    resolveImageUrl<Product>(data.msg, (obj) => obj.imgurl, (obj, resolvedUrl) => obj.imgurl = resolvedUrl);
    return data.msg;
  }

  @override
  Future<CountResult> getAllSupplierCount(String token) async {
    var response = await dio0.post("/supplier/pager?token=$token");
    globalBus.publish(NETWORK_COMMUNICATION_RESPONSE,response);
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => CountResult.fromJson(json));
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<List<Supplier>> getSuppliers(String token, [int pageIndex = 0]) async {
    var response = await dio0.post("/supplier/select?token=$token", options: Options(
      headers: {
        "page": pageIndex
      }
    ));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => (json as List<dynamic>).map((json) => Supplier.fromJson(json)).toList());
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<List<SupplierType>> getAllSupplierTypes(String token) async {
    var response = await dio0.post("/suppliertype/get?token=$token");
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => (json as List<dynamic>).map((item) => SupplierType.fromJson(item)).toList());
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<SupplierType> addSupplierType(String token, SupplierType data) async {
    var response = await dio0.post("/suppliertype/add?token=$token", data: FormData.from(data.toJson()));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var responseData = ServerResponse.fromJson(resolveToJson(response.data), (json) => SupplierType.fromJson(json));
    if (!responseData.type) throw responseData.msgText;
    return responseData.msg;
  }

  @override
  Future<SupplierType> deleteSupplierType(String token, SupplierType supplierType) async {
    var response = await dio0.post("/suppliertype/delete?token=$token", data: FormData.from({
      "id": supplierType.id
    }));

    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => null);
    if (!data.type) throw data.msgText;

    return supplierType;
  }

  @override
  Future<SupplierType> updateSupplierType(String token, SupplierType data) async {
    var response = await dio0.post("/suppliertype/edit?token=$token", data: FormData.from(data.toJson()));
    globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var responseData = ServerResponse.fromJson(resolveToJson(response.data), (json) => null);
    if (!responseData.type) throw responseData.msgText;
    return data;
  }

  @override
  Future<Supplier> addSupplier(String token, Supplier supplier) async {
    var response = await dio0.post("/supplier/add?token=$token", data: FormData.from(supplier.toJson()));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => Supplier.fromJson(json));
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<Supplier> deleteSupplier(String token, Supplier supplier) async {
    var response = await dio0.post("/supplier/delete?token=$token", data: FormData.from({
      "id": supplier.id
    }));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => null);
    if (!data.type) throw data.msgText;
    return supplier;
  }

  @override
  Future<Supplier> updateSupplier(String token, Supplier supplier) async {
    var response = await dio0.post("/supplier/edit?token=$token", data: FormData.from(supplier.toJson()));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => Supplier.fromJson(json));
    if (!data.type) throw data.msgText;
    return supplier;
  }

  @override
  Future<WareHouse> addWareHouses(String token, WareHouse data) async {
    var response = await dio0.post("/warehouse/add?token=$token", data: FormData.from(data.toJson()));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var responseData = ServerResponse.fromJson(resolveToJson(response.data), (json) => WareHouse.fromJson(json));
    if (!responseData.type) throw responseData.msgText;
    return responseData.msg;
  }

  @override
  Future<WareHouse> deleteWareHouses(String token, WareHouse data) async {
    var response = await dio0.post("/warehouse/delete?token=$token", data: FormData.from({
      "id": data.id
    }));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var responseData = ServerResponse.fromJson(resolveToJson(response.data), (json) => null);
    if (!responseData.type) throw responseData.msgText;
    return data;
  }

  @override
  Future<CountResult> getAllWareHouseCount(String token) async {
    var response = await dio0.post("/warehouse/pager?token=$token");
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var responseData = ServerResponse.fromJson(resolveToJson(response.data), (json) => CountResult.fromJson(json));
    if (!responseData.type) throw responseData.msgText;
    return responseData.msg;
  }

  @override
  Future<List<WareHouse>> getWareHouses(String token, [int pageIndex = 0]) async {
    var response = await dio0.post("/warehouse/select?token=$token", options: Options(
      headers: {
        "page": pageIndex
      }
    ));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var responseData = ServerResponse.fromJson(resolveToJson(response.data), (json) => (json as List<dynamic>).map((json) => WareHouse.fromJson(json)).toList());
    if (!responseData.type) throw responseData.msgText;
    return responseData.msg;
  }

  @override
  Future<WareHouse> updateWareHouses(String token, WareHouse data) async {
    var response = await dio0.post("/warehouse/edit?token=$token", data: FormData.from(data.toJson()));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var responseData = ServerResponse.fromJson(resolveToJson(response.data), (json) => WareHouse.fromJson(json));
    if (!responseData.type) throw responseData.msgText;
    return responseData.msg;
  }

  @override
  Future<CountResult> getAllPurchaseOrderCount(String token) async {
    var response = await dio0.post("/purchase/pager?token=$token");
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => CountResult.fromJson(json));
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<PurchaseOrder> addPurchaseOrder(String token, PurchaseOrder order) async {
    var response = await dio0.post("/purchase/purchase?token=$token", data: FormData.from({
      "amount": order.amount,
      "samount": order.sAmount,
      "supplier": order.supplier,
      "potime": DateFormat("yyyy-MM-dd HH:mm:ss").format(DateTime.now()),
      "repaydate": order.repayDate,
      "employee": order.employee,
      "memo": "",
      "items": json.encode(order.products)
    }));

    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => json);
    if (!data.type) throw data.msgText;
    order.orderNumber = resolveToJson(data.msg)["pono"];
    return order;
  }

  @override
  Future<List<PurchaseOrder>> getPurchaseOrders(String token, [int pageIndex = 0]) async {
    var response = await dio0.post("/purchase/select?token=$token", data: FormData.from(
      {
        "page": pageIndex
      }
    ));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) =>(json as List<dynamic>).map((item) => PurchaseOrder.fromJson(item)).toList());
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<List<ProductDetailAtPurchaseOrSell>> getPurchaseOrderDetails(String token, PurchaseOrder order) async {
    var response = await dio0.post("/purchase/getdetailsbypono?token=$token", data: FormData.from(
        {
          "pono": order.orderNumber
        }
    ));
    response = globalBus.publish(NETWORK_COMMUNICATION_RESPONSE, response);
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) =>(json as List<dynamic>).map((item) => ProductDetailAtPurchaseOrSell.fromJson(item)).toList());
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<List<ProductDetailAtPurchaseOrSell>> getProductsInPurchaseOrder(String token, PurchaseOrder order) async {
    var response = await dio0.post("/purchase/getdetailsbypono?token=$token", data: FormData.from({
      "pono": order.orderNumber
    }));

    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => (json as List<dynamic>).map((json) => ProductDetailAtPurchaseOrSell.fromJson(json)).toList());
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<List<CustomerType>> getCustomerTypes(String token) async {
    var response = await dio0.post("/customertype/get?token=${token}");
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => (json as List<dynamic>).map((json) => CustomerType.fromJson(json)).toList());
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<CustomerType> addCustomerType(String token, CustomerType customerType) async {
    var response = await dio0.post("/customertype/add?token=${token}", data: FormData.from({
      "name": customerType.name,
      "memo": customerType.memo
    }));

    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => CustomerType.fromJson(json));
    if (!data.type) throw data.msgText;

    return data.msg;
  }

  @override

  Future<bool> deleteCustomerType(String token, CustomerType customerType) async {
    var response = await dio0.post("/customertype/delete?token=${token}", data: FormData.from({
      "id": customerType.id
    }));

    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => json);
    if (!data.type) throw data.msgText;
    return true;
  }

  @override
  Future<CustomerType> updateCustomerType(String token, CustomerType customerType) async {
    var response = await dio0.post("/customertype/edit?token=${token}", data: FormData.from({
      "id": customerType.id,
      "name": customerType.name,
      "memo": customerType.memo
    }));

    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => json);
    if (!data.type) throw data.msgText;
    return customerType;
  }

  @override
  Future<Customer> addCustomer(String token, Customer customer) async {
    var response = await dio0.post("/customer/add?token=$token", data: FormData.from({
      "name": customer.name,
      "phone": customer.phone,
      "type": customer.type,
      "memo": customer.memo,
    }));

    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => Customer.fromJson(json));
    if (!data.type) throw data.msgText;

    return data.msg;
  }

  @override
  Future<Customer> deleteCustomer(String token, Customer customer) async {
    var response = await dio0.post("/customer/delete?token=$token", data: FormData.from({
      "id": customer.id
    }));

    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => json);
    if (!data.type) throw data.msgText;
    return customer;
  }

  @override
  Future<List<Customer>> getAllCustomers(String token) async {
    var response = await dio0.post("/customer/select?token=$token");
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => (json as List<dynamic>).map((json) => Customer.fromJson(json)).toList());
    if (!data.type) throw data.msgText;

    return data.msg;
  }

  @override
  Future<Customer> updateCustomer(String token, Customer customer) async {
    var response = await dio0.post("/customer/edit?token=$token", data: FormData.from({
      "id": customer.id,
      "name": customer.name,
      "phone": customer.phone,
      "type": customer.type,
      "memo": customer.memo,
    }));

    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => json);
    if (!data.type) throw data.msgText;

    return customer;
  }

  @override
  Future<List<SalesOrder>> getAllSalesOrders(String token) async {
    var response = await dio0.post("/sales/select?token=$token");
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => (json as List<dynamic>).map((json) => SalesOrder.fromJson(json)).toList());

    if (!data.type) throw data.msgText;

    return data.msg;
  }

  @override
  Future<List<ProductDetailAtPurchaseOrSell>> getProductGroupsInSalesOrder(String token, SalesOrder order) async {
    var response = await dio0.post("/sales/getdetailsbysono?token=$token", data: FormData.from({
      "sono": order.orderNumber
    }));

    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => (json as List<dynamic>).map((json) => ProductDetailAtPurchaseOrSell.fromJson(json)).toList());
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<SalesOrder> addSalesOrder(String token, SalesOrder order) async {
    var response = await dio0.post("/sales/sales?token=$token", data: FormData.from({
      "amount": order.amount,
      "samount": order.sAmount,
      "sotime": order.time,
      "repaydate": order.repayDate ?? DateTime(1964),
      "employee": order.employee,
      "customer": order.customer,
      "items": json.encode(order.products),
    }));

    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => (json as Map<String, dynamic>)["sono"]);
    if (!data.type) throw data.msgText;

    var insertedOrder = await dio0.post("/sales/search?token=$token", data: FormData.from({"sono": data.msg}));
    var selectedData = ServerResponse.fromJson(resolveToJson(insertedOrder.data), (json) => SalesOrder.fromJson((json as List<dynamic>).first));
    if (!selectedData.type) throw selectedData.msgText;
    return selectedData.msg;
  }

  @override
  Future<List<ProductInWareHouse>> getAllProductsInWareHouse(String token) async {
    var response = await dio0.post("/probalance/getall?token=$token");
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => (json as List<dynamic>).map((json) => ProductInWareHouse.fromJson(json)).toList());
    data.msg.forEach((item) => resolveImageUrl<ProductInWareHouse>(item, (item) => item.imgUrl, (item, resolved) => item.imgUrl = resolved));
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<ProductInWareHouse> editProductInWareHouse(String token, ProductInWareHouse product) async {
    var formData = {
      "edittime": toDate(DateTime.now()),
      "employee": AccountStore.signInResult.id,
      "procode": product.code,
      "proname": product.nameUg,
      "attach": product.attach,
      "warehouse": product.warehouse,
      "editcount": product.balanceCount - product.oldBalanceCount,
      "beforecount": product.oldBalanceCount,
      "proisbn": product.barCode,
      "memo": product.comment
    };
    var response = await dio0.post("/probalance/editbalance?token=$token", data: FormData.from(formData));

    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => ProductInWareHouse.fromJson(json));
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<ProductInWareHouse> editPriceOfProductInWareHouse(String token, ProductInWareHouse product) async {
    var formData = {
      "updatetime": toDate(DateTime.now()),
      "employee": AccountStore.signInResult.id,
      "procode": product.code,
      "proname": product.nameUg,
      "oldattach": product.attach,
      "logattach": product.attach,
      "newattach": makeAttach(parseAttach(product.attach).sellPrice, product.sellPrice),
      "warehouse": product.warehouse,
      "proisbn": product.barCode,
      "memo": product.comment
    };
    var response = await dio0.post("/probalance/updateprice?token=$token", data: FormData.from(formData));

//    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => ProductInWareHouse.fromJson(json));
    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => ProductInWareHouse.fromJson(json));
    if (!data.type) throw data.msgText;
    return data.msg;
  }

  @override
  Future<ProductInWareHouse> deleteProductInWareHouse(String token, ProductInWareHouse product) async {
    var response = await dio0.post("/probalance/delete?token=$token", data: FormData.from({
      "id": product.id
    }));

    var data = ServerResponse.fromJson(resolveToJson(response.data), (json) => json);
    if (!data.type) throw data.msgText;

    return product;
  }
}




